import qs from "qs";
import { notNilEmpty } from "qx-util";
import {
  RouteConst,
  ViewType,
  calcDeCodeNameById,
  getMatchResPath,
} from "@ibiz-template/runtime";
import type { IViewConfig } from "@ibiz-template/runtime";
import { RuntimeError } from "@ibiz-template/core";
import type { IRouteViewData, IRoutePathNode, IRoutePath } from "@/interface";
import { getAllPages } from "../util/util";

/**
 * 动态页面路径
 */
export const DYNAMIC_PAGE_PATH = getAllPages("dynamicPage", true).map(
  (page) => page.path
)[0];

/**
 * 首页路径
 */
export const HOME_PAGE_PATH = getAllPages("homePage", true).map(
  (page) => page.path
)[0];

/**
 * 登录页面路径
 */
export const LOGIN_ROUTE_PATH = getAllPages("loginPage", true).map(
  (page) => page.path
)[0];

/**
 * 首页根路径
 */
export const HOME_ROOT_PATH = "/-/index/-";

/**
 * 路由数据
 */
export type Route = {
  path: string;
  fullPath: string;
  query: Record<string, string>;
};

const excludeViewTypes: string[] = [
  ViewType.DE_MOB_MDVIEW,
  ViewType.DE_MOB_LIST_VIEW,
  ViewType.DE_MOB_LIST_EXP_VIEW,
  ViewType.DE_MOB_DATA_VIEW,
  ViewType.DE_MOB_DATA_VIEW_EXP_VIEW,
  ViewType.DE_MOB_CALENDAR_VIEW,
  ViewType.DE_MOB_CALENDAR_EXP_VIEW,
  ViewType.DE_MO_CHART_VIEW,
  ViewType.DE_MOB_CHART_EXP_VIEW,
];

/**
 * 统一 decodeURIComponent ，兼容h5和微信
 * @param str
 * @returns
 */
function ensureDecodeURIComponent(str: string): string {
  if (str && str.startsWith("%")) {
    return ensureDecodeURIComponent(decodeURIComponent(str));
  }
  return str;
}

/**
 * 获取自身的路由上下文，排除了部分不需要路由携带的参数
 * @param context
 * @returns
 */
function getOwnRouteContext(context: IContext): IParams {
  const ownContext = context.getOwnContext();
  const excludeKeys = [
    "srfsessionid",
    "srfappid",
    "currentSrfNav",
    "toRouteDepth",
  ];
  Object.keys(ownContext).forEach((key) => {
    if (excludeKeys.includes(key)) {
      delete ownContext[key];
    }
  });
  return ownContext;
}

/**
 * 附加预置参数
 * @param context
 * @param pathNodes
 */
function attachPresetParams(
  context: IContext,
  pathNodes: IRoutePathNode[]
): void {
  // 处理预置参数srfreadonly,设置上下文srfreadonly参数
  // 祖先存在srfreadonly=true则不需处理；如果都没有，当前父环境srfreadonly=true，则需给当前环境设置srfreadonly=true
  let index = -1;
  if (pathNodes && pathNodes.length > 0) {
    index = pathNodes.findIndex((pathNode) => {
      return pathNode.context?.srfreadonly === true;
    });
  }
  if (
    context.srfreadonly &&
    !context.getOwnContext().srfreadonly &&
    index === -1
  ) {
    context.srfreadonly = true;
  }
}

/**
 * 计算资源路径,把首页后面的资源路径上下文算出来，并把第二层中对应的上下文删掉。
 * @param routePath
 * @param context
 * @param appDataEntityId
 * @param appId
 */
export async function calcResRoutePath(
  routePath: IRoutePath,
  context: IContext,
  appDataEntityId?: string,
  appId?: string
): Promise<void> {
  if (!appDataEntityId) {
    // 无实体的视图清空资源上下文
    routePath.pathNodes[0].context = undefined;
  } else {
    const entity = await ibiz.hub.getAppDataEntity(appDataEntityId, appId);
    let match = getMatchResPath(context, entity);
    // 有实体有没有匹配到的，补一个包含自身实体主键的match
    if (!match) {
      match = { path: "", keys: [entity.codeName!.toLowerCase()] };
    }
    if (match) {
      const currentContext = routePath.pathNodes[1].context;
      const resContext: IParams = {};
      // 资源路径不为空,二级视图的上下文删掉多余的资源上下文
      match.keys.forEach((key) => {
        if (context && Object.prototype.hasOwnProperty.call(context, key)) {
          resContext[key] = context[key];
          if (currentContext) {
            delete currentContext[key];
          }
        }
      });
      // 把资源路径填充到一级路由上
      routePath.pathNodes[0].context = resContext;
    }
  }
}

/**
 * 解析路径为路由数据
 *
 * @export
 * @param {string} fullPath
 * @return {*}  {Route}
 */
export function parsePath(fullPath: string): Route {
  const [path, queryStr] = fullPath.split("?");
  const query: Record<string, string> = {};
  if (queryStr) {
    (queryStr as string).split("&").forEach((item) => {
      const [key, value] = item.split("=");
      query[key] = ensureDecodeURIComponent(value);
    });
  }
  return { path, fullPath, query };
}

/**
 * 当前路由对象
 * @returns
 */
export function currentRoute(): Route {
  const pages = getCurrentPages();
  const lastPage = pages[pages.length - 1];
  const { fullPath } = (lastPage as any).$page;
  return parsePath(fullPath);
}

/**
 * 路由路径转成路由路径对象
 * @param isRouteModal
 */
export function route2routePath(
  route: Route,
  isRouteModal: boolean = false
): IRoutePath {
  const { query } = route;
  let path = query.fullPath || HOME_ROOT_PATH;
  if (isRouteModal) {
    path = path.replace(new RegExp(`/${RouteConst.ROUTE_MODAL_TAG}`, "g"), "");
  }
  const items = path.split("/");
  const depth = items.length / 2 - 1;
  const pathNodes: IRoutePathNode[] = [];
  for (let index = 1; index <= depth; index++) {
    const viewName = items[index * 2];
    const paramsStr = items[index * 2 + 1];

    /** 路由参数，默认是视图参数 */
    let params: IParams | undefined;

    /** 上下文参数 */
    let context: IParams | undefined;
    let srfnav: string | undefined;
    // params为占位符时置空
    if (!paramsStr || paramsStr === ibiz.env.routePlaceholder) {
      params = undefined;
    } else {
      params = {};
      paramsStr.split("&").forEach((item) => {
        const [key, value] = item.split("=");
        params![key] = ensureDecodeURIComponent(value);
      });
    }

    // 路由参数存在的时候，解析里面的上下文。
    if (params) {
      if (index === 1) {
        // 首页的时候，路由上的参数是资源路径，属于上下文
        context = params;
        params = undefined;
      } else {
        if (params.srfnavctx) {
          // 解析额外上下文
          context = JSON.parse(params.srfnavctx);
          delete params.srfnavctx;
        }
        if (params.srfnav) {
          // 解析额外自身视图导航参数
          srfnav = params.srfnav;
          delete params.srfnav;
        }
      }
    }

    pathNodes.push({ viewName, context, params, srfnav });
  }
  // TODO 应用上下文
  let appContext;
  return { appContext, pathNodes };
}

/**
 * 路由路径对象转路径字符串
 * @param routePath
 * @returns
 */
export function routePath2string(routePath: IRoutePath): string {
  let pathStr = "";
  // 应用上下文
  if (routePath.appContext) {
    pathStr += `/${qs.stringify(routePath.appContext, {
      delimiter: ";",
      strictNullHandling: true,
    })}`;
  } else {
    pathStr += `/${ibiz.env.routePlaceholder}`;
  }

  // 每一层级的视图路由的拼装
  routePath.pathNodes.forEach((pathNode: IRoutePathNode, index: number) => {
    pathStr += `/${pathNode.viewName}/`;
    let routeParams: IParams = {};
    // 首页路由
    if (index === 0) {
      if (notNilEmpty(pathNode.context)) {
        // 对象转成a=11;b=222的格式，字符串直接附加在后面
        routeParams = pathNode.context!;
      }
    } else {
      // 非首页路由,视图参数直接放到路由参数上，上下文转换后放到路由参数的srfnavctx上
      routeParams = notNilEmpty(pathNode.params) ? pathNode.params! : {};

      // 合并视图上下文
      if (notNilEmpty(pathNode.context)) {
        const objStr = JSON.stringify(pathNode.context);
        // undefined 的vlaue会被JSON.stringify删除,可能会转成{}
        if (objStr !== "{}") {
          routeParams!.srfnavctx = encodeURIComponent(objStr);
        }
      }

      // 合并视图导航参数
      if (pathNode.srfnav) {
        routeParams.srfnav = pathNode.srfnav;
      }
    }

    const paramsStr = qs.stringify(routeParams, {
      delimiter: ";",
      strictNullHandling: true,
      skipNulls: true,
    });
    // 把路由参数转换到路由路径上去
    if (notNilEmpty(paramsStr)) {
      pathStr += paramsStr;
    } else {
      pathStr += ibiz.env.routePlaceholder;
    }
  });

  return pathStr;
}

/**
 * 解析路由视图数据
 * @param isRouteModal
 */
export async function parseRouteViewData(
  route: Route,
  isRouteModal: boolean = false
): Promise<IRouteViewData> {
  // 解析路由的视图参数
  const routePath = route2routePath(route, isRouteModal);
  const depth = routePath.pathNodes.length;
  // 获取对应层级的视图名称参数
  let viewCodeName = routePath.pathNodes[depth - 1].viewName;
  if (!viewCodeName) {
    throw new RuntimeError(
      ibiz.i18n.t("utils.route.noViewIdentity", {
        depth,
      })
    );
  }
  if (viewCodeName === RouteConst.ROUTE_MODAL_TAG) {
    viewCodeName = routePath.pathNodes[depth].viewName;
  }
  if (viewCodeName === "index") {
    viewCodeName = ibiz.hub.defaultAppIndexViewName;
  }
  const viewConfig = await ibiz.hub.config.view.get(viewCodeName);
  if (!viewConfig) {
    throw new RuntimeError(ibiz.i18n.t("common.noFoundViewModel"));
  }

  // !解析上下文参数,整合当前层级之前所有的上下文参数
  const context: IParams = {};
  // 合并appData里的应用上下文
  if (ibiz.appData?.context) {
    Object.assign(context, ibiz.appData.context);
  }

  // 合并路由上下文
  // 合并路由应用上下文
  if (routePath.appContext) {
    Object.assign(context, routePath.appContext);
  }

  // 逐层合并视图上下文,第一层首页不合，它的上下文是资源路径属于子视图。
  if (depth !== 1) {
    for (let index = 0; index < depth; index++) {
      const pathNode = routePath.pathNodes[index];
      if (notNilEmpty(pathNode.context)) {
        Object.assign(context, pathNode.context);
      }
    }
  }

  // 最后一级路由对应的视图才会解析视图参数
  const { params, srfnav } = routePath.pathNodes[depth - 1];

  return {
    viewConfig,
    context,
    params,
    srfnav,
  };
}

/**
 * 生成路由路径
 * @param appView
 * @param context
 * @param params
 * @returns
 */
export async function generateRoutePath(
  appView: IViewConfig,
  route: Route,
  context: IContext,
  params?: IParams
) {
  // 解析路由的视图参数
  const routePath = route2routePath(route);
  let depth = context.srfdefaulttoroutedepth || 2; // 默认层级看上下文的srfdefaulttoroutedepth，如果没有就是2
  if (context.toRouteDepth) {
    depth = context.toRouteDepth;
    // 使用完后转为undefined，避免添加到上下文里
    context.toRouteDepth = undefined;
  } else if (ibiz.env.isMob) {
    // 移动端默认补充home层级
    routePath.pathNodes[0] = {
      viewName: "home",
    };
  }
  // 删除目标层级和之后的路由，保留之前层级的路由
  routePath.pathNodes.splice(depth - 1, routePath.pathNodes.length - depth + 1);

  // 导航视图的导航参数,加在目标层级之前的一个层级的视图参数里
  if (context.currentSrfNav) {
    const currentNode = routePath.pathNodes[routePath.pathNodes.length - 1];
    currentNode.params = currentNode.params || {};
    currentNode.srfnav = context.currentSrfNav;
    // 使用完后转为undefined，避免添加到上下文里
    context.currentSrfNav = undefined;
  }

  // 附加当前环境上下文的srfreadonly
  attachPresetParams(context, routePath.pathNodes);

  const { query } = route;

  if (query.fullPath?.startsWith("/appredirectview")) {
    if (params?.srfindexname) {
      routePath.pathNodes[0].viewName = params.srfindexname;
      delete params.srfindexname;
    } else {
      routePath.pathNodes[0].viewName = "index";
    }
  }

  // 计算目标视图path路径
  routePath.pathNodes.push({
    viewName: appView.codeName!.toLowerCase(),
    context: getOwnRouteContext(context),
    params,
  });

  // 计算二级视图的资源路径加到index后面
  if (depth === 2) {
    await calcResRoutePath(
      routePath,
      context,
      appView.appDataEntityId,
      appView.appId
    );

    // 多数据和导航视图，删除自身的主键上下文
    if (excludeViewTypes.includes(appView.viewType)) {
      const deName = calcDeCodeNameById(appView.appDataEntityId!);
      delete routePath.pathNodes[0].context![deName];
    }
  }

  const ROOT_PATH =
    routePath.pathNodes[0].viewName === "index"
      ? HOME_PAGE_PATH
      : DYNAMIC_PAGE_PATH;
  return {
    path: `${ROOT_PATH}?fullPath=${encodeURIComponent(
      routePath2string(routePath)
    )}`,
  };
}
